package com.ztn.iot.zhonghaichi.fun;

import com.ztn.base.util.common.TimeTool;
import com.ztn.iot.zhonghaichi.entity.IotDeviceEntity;
import com.ztn.iot.zhonghaichi.entity.SiteEntity;
import com.ztn.iot.zhonghaichi.properties.ZhcProperties;
import com.ztn.iot.zhonghaichi.push.DataPushApi;
import com.ztn.iot.zhonghaichi.push.TokenGetApi;
import com.ztn.iot.zhonghaichi.service.IIotDeviceService;
import com.ztn.iot.zhonghaichi.service.ISiteService;
import com.ztn.sdk.iot.api.IotDeviceExplainTool;
import com.ztn.sdk.iot.api.IotDeviceParamTool;
import com.ztn.sdk.iot.api.req.DeviceExplainListReq;
import com.ztn.sdk.iot.api.req.DeviceParamListReq;
import com.ztn.sdk.iot.api.res.DeviceExplain;
import com.ztn.sdk.iot.api.res.DeviceParam;
import com.ztn.sdk.iot.api.util.HttpTool;
import com.ztn.sdk.iot.api.util.JsonTool;
import com.ztn.sdk.iot.hook.HookTool;
import com.ztn.sdk.iot.hook.bean.IotSystemHookWarp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeoutException;

@Slf4j
@Component
@EnableScheduling
public class SensorFun {

    @Autowired
    private ISiteService siteService;

    @Autowired
    private IIotDeviceService iotDeviceService;

    @Autowired
    private DataPushApi dataPushApi;

    @Autowired
    private TokenGetApi tokenGetApi;

    @Autowired
    private ZhcProperties zhcProperties;


    public static final String EXPLAIN_KEY_NAME_RAIN = "eRainfall";
    public static final String EXPLAIN_KEY_NAME_WATER_DEPT = "eWDepth";
    public static final String EXPLAIN_KEY_NAME_SEEP_FLOW = "eSeepFlow";

    public static final String PARAM_KEY_NAME_SITE_STORAGE = "siteStorage";
    public static final String PARAM_KEY_NAME_SITE_CODE = "siteCode";
    public static final String PARAM_KEY_NAME_WARN_WATER_DEPT = "warnWaterDept";

    public static final String PARAM_KEY_NAME_DEFAULT_WATER_DEPT = "defaultEWDepth";
    public static final String PARAM_KEY_NAME_DEFAULT_SEEP_RATIO = "defaultSeepRatio";
    public static final String PARAM_KEY_NAME_DEFAULT_RAIN = "defaultRainfall";

    //[ERROR] com.ztn.base.util.common.HttpClientTool.postJsonStrWithHeaderForRes(HttpClientTool.java:281) 2023-05-06 21:51:39,078 com.ztn.base.util.common.HttpClientTool - http://210.76.77.28/SkDataApi/receive/rain,error:Timeout waiting for connection from pool
    //java.lang.NullPointerException

    @PostConstruct
    public void init() {
        log.info(JsonTool.toJson(zhcProperties));
        HttpTool.setToken(zhcProperties.getIotApiToken());
        updateToken();
        m15Job();
        new Thread(() -> {
            HookTool.IS_DURABLE = false;
            HookTool hookRabbit = new HookTool();
            try {
                hookRabbit.connect(zhcProperties.getIotMqTopic(), this::handler); //"exchange.zhonghaichi"
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
        }).start();
    }

    @Scheduled(cron = "0 0/20 * * * ? ")
    public void updateTokenJob() {
        log.info("updateTokenJob()");
        updateToken();
    }

    public void updateToken() {
//        TokenGetReq req = new TokenGetReq();
//        req.setUsername("赫章中海驰安防科技有限公司");
//        req.setUsercode("0547c53805f036b75d238a24d12e0e3c");
        tokenGetApi.getToken();
    }

    /**
     * 每一个小时
     */
    @Scheduled(cron = "0 0 0/1 * * ? ")
    public void hourJob() {
        log.info("hourJob");
        siteService.list().forEach(siteEntity -> {
            doJob(siteEntity);
            SiteEntity siteSave = new SiteEntity();
            siteSave.setSiteId(siteEntity.getSiteId());
            siteSave.setLastHourRainCount(siteEntity.getRainCount());
            siteService.update(siteSave);

        });
    }

    /**
     * 每天8点
     */
    @Scheduled(cron = "0 0 8 * * ? ")
    public void dayJob() {
        log.info("dayJob");
        siteService.list().forEach(siteEntity -> {
            doJob(siteEntity);
            SiteEntity siteSave = new SiteEntity();
            siteSave.setSiteId(siteEntity.getSiteId());
            siteSave.setLastDayRainCount(siteEntity.getRainCount());
            siteService.update(siteSave);
        });
    }

    @Scheduled(cron = "0 0/15 * * * ? ")
    public void m15Job() {
        log.info("m15Job");
        new Thread(() -> {
            iotDeviceService.listAll().forEach(deviceEntity -> {
                renewDeviceInfo(deviceEntity.getDeviceCore());
            });
        }).start();

    }


    void doJob(SiteEntity siteEntity) {
        if (!StringUtils.hasText(siteEntity.getSiteCode())) {
            return;
        }
        BigDecimal bdLastDayRainCount = BigDecimal.valueOf(siteEntity.getLastDayRainCount());
        BigDecimal bdLastHourRainCount = BigDecimal.valueOf(siteEntity.getLastHourRainCount());
        BigDecimal bdLastRainCount = BigDecimal.valueOf(siteEntity.getLastRainCount());
        BigDecimal bdRainCount = BigDecimal.valueOf(siteEntity.getRainCount());

        final double rainCount = bdRainCount.doubleValue();
        final double lastHourRainCount = bdLastHourRainCount.doubleValue();
        final double lastDayRainCount = bdLastDayRainCount.doubleValue();
        final double lastRainCount = bdLastRainCount.doubleValue();

        int time = TimeTool.time();
        dataPushApi.pushRain(time, siteEntity.getSiteCode(), rainCount - lastRainCount, rainCount - lastHourRainCount, rainCount - lastDayRainCount);
        dataPushApi.pushWater(time, siteEntity.getSiteCode(), siteEntity.getWaterDept(), siteEntity.getSiteStorage(), null, null, siteEntity.getWarnWaterDept());

        if (siteEntity.getSiteStorage().equals(0)) {
            dataPushApi.pushFlow(time, siteEntity.getSiteCode(), 0D, siteEntity.getWaterFlow(), siteEntity.getWarnWaterDept(), null);
        } else {
            dataPushApi.pushFlow(time, siteEntity.getSiteCode(), null, siteEntity.getWaterFlow(), siteEntity.getWarnWaterDept(), null);
        }

    }


    void doHandler(String topic, IotSystemHookWarp iotSystemHookWarp) {
        String deviceCore = iotSystemHookWarp.getDeviceCore();
        renewDeviceInfo(deviceCore);
    }

    void renewDeviceInfo(String deviceCore) {
        DeviceParamListReq req = new DeviceParamListReq();
        req.setDeviceCore(deviceCore);
        final List<DeviceParam> deviceParamList = IotDeviceParamTool.list(req);

        String siteCode = null;
        for (DeviceParam deviceParam : deviceParamList) {
            if (deviceParam.getKeyName().equals(PARAM_KEY_NAME_SITE_CODE)) {
                if (null != deviceParam.getValue() && StringUtils.hasText(deviceParam.getValue().toString())) {
                    siteCode = deviceParam.getValue().toString();
                }
            }
        }

        SiteEntity siteDb;
        if (StringUtils.hasText(siteCode)) {
            siteDb = siteService.getBySiteCode(siteCode);
        } else {
            return;
        }

        SiteEntity siteSave = new SiteEntity();
        if (null == siteDb) {
            if (StringUtils.hasText(siteCode)) {
                log.info("try insert site {}", siteCode);
                siteSave.setSiteCode(siteCode);
                siteService.insert(siteSave);
                siteDb = siteService.getBySiteCode(siteCode);
            } else {
                log.error("{} site is not exist", siteCode);
                return;
            }
        }

        if (null == siteDb) {
            log.error("insert site error {}", siteCode);
        }

        DeviceExplainListReq deviceExplainListReq = new DeviceExplainListReq();
        deviceExplainListReq.setDeviceCore(deviceCore);
        final List<DeviceExplain> deviceExplainList = IotDeviceExplainTool.list(deviceExplainListReq);
        deviceExplainList.forEach(sensorExplain -> {
            try {
                switch (sensorExplain.getKeyName()) {
                    case EXPLAIN_KEY_NAME_RAIN:
                        if (null != sensorExplain.getValue() && StringUtils.hasText(sensorExplain.getValue().toString())) {
                            siteSave.setRainCount(Double.parseDouble(sensorExplain.getValue().toString()));
                        }
                        break;
                    case EXPLAIN_KEY_NAME_WATER_DEPT:
                        if (null != sensorExplain.getValue() && StringUtils.hasText(sensorExplain.getValue().toString())) {
                            siteSave.setWaterDept(Double.parseDouble(sensorExplain.getValue().toString()));
                        }
                        break;
                    case EXPLAIN_KEY_NAME_SEEP_FLOW:
                        if (null != sensorExplain.getValue() && StringUtils.hasText(sensorExplain.getValue().toString())) {
                            siteSave.setWaterFlow(Double.parseDouble(sensorExplain.getValue().toString()));
                        }
                        break;
                    default:
                }
            } catch (Exception e) {
                log.error("", e);
            }
        });


        for (DeviceParam deviceParam : deviceParamList) {
            try {

                switch (deviceParam.getKeyName()) {
                    case PARAM_KEY_NAME_SITE_STORAGE:
                        if (null != deviceParam.getValue() && StringUtils.hasText(deviceParam.getValue().toString())) {
                            siteSave.setSiteStorage(Double.parseDouble(deviceParam.getValue().toString()));
                        }
                        break;
                    case PARAM_KEY_NAME_WARN_WATER_DEPT:
                        if (null != deviceParam.getValue() && StringUtils.hasText(deviceParam.getValue().toString())) {
                            siteSave.setWarnWaterDept(Double.parseDouble(deviceParam.getValue().toString()));
                        }
                        break;
                    case PARAM_KEY_NAME_DEFAULT_RAIN:
                        if (null != deviceParam.getValue() && StringUtils.hasText(deviceParam.getValue().toString())) {
                            siteSave.setRainCount(siteDb.getRainCount() + Double.parseDouble(deviceParam.getValue().toString()));
                        }
                        break;
                    case PARAM_KEY_NAME_DEFAULT_WATER_DEPT:
                        if (null != deviceParam.getValue() && StringUtils.hasText(deviceParam.getValue().toString())) {
                            siteSave.setWaterDept(Double.parseDouble(deviceParam.getValue().toString()));
                        }
                        break;
                    case PARAM_KEY_NAME_DEFAULT_SEEP_RATIO:
                        if (null != deviceParam.getValue() && StringUtils.hasText(deviceParam.getValue().toString())) {
                            siteSave.setWaterFlow(Double.parseDouble(deviceParam.getValue().toString()));
                        }
                        break;
                    default:
                }
            } catch (Exception e) {
                log.error("", e);
            }
        }
        siteSave.setSiteId(siteDb.getSiteId());


        IotDeviceEntity iotDeviceEntity = iotDeviceService.getByDeviceCode(deviceCore);
        if (null == iotDeviceEntity) {
            IotDeviceEntity iotDeviceSave = new IotDeviceEntity();
            iotDeviceSave.setDeviceCore(deviceCore);
            iotDeviceSave.setSiteId(siteSave.getSiteId());
            iotDeviceService.insert(iotDeviceSave);
        } else {
            if (!iotDeviceEntity.getSiteId().equals(siteSave.getSiteId())) {
                IotDeviceEntity iotDeviceSave = new IotDeviceEntity();
                iotDeviceSave.setId(iotDeviceEntity.getId());
                iotDeviceSave.setSiteId(siteSave.getSiteId());
                iotDeviceService.update(iotDeviceSave);
            }
        }

        if (siteDb.getLastHourRainCount().equals(0D)) {
            siteSave.setLastHourRainCount(siteSave.getRainCount());
        }
        if (siteDb.getLastDayRainCount().equals(0D)) {
            siteSave.setLastDayRainCount(siteSave.getRainCount());
        }
        if (siteDb.getLastRainCount().equals(0D)) {
            siteSave.setLastRainCount(siteSave.getRainCount());
        } else {
            siteSave.setLastRainCount(siteDb.getRainCount());
        }
        siteService.update(siteSave);
//        siteDb = siteService.getBySiteCode(siteCode);
//        doJob(siteDb);

    }

    public void handler(String topic, IotSystemHookWarp iotSystemHookWarp) {
        try {
            doHandler(topic, iotSystemHookWarp);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
